// TODO

#pragma once

#include "../Utility/Log/Log.hpp"
#include "../Utility/Util/utility.hpp"
#include "../Utility/httplib.h"
#include "../Utility/Data/Time/TimeFactory.hpp"

namespace ns_Server
{
    using namespace httplib;
    using namespace ns_Log;
    using namespace ns_Util;
    using namespace ns_Time;

    class ServerControl
    {
    public:
        static bool SinglePointPosition(const std::string &inJson, std::string *outJson)
        {
            Client mesInput("127.0.0.1", 8100);
            Client obsInput("127.0.0.1", 8200);
            Client calculate("127.0.0.1", 8000);

            Json::Reader reader;
            Json::Value inValue;
            if (!reader.parse(inJson, inValue))
                return false;

            std::string fileName = inValue["FileName"].asString();
            unsigned int year = inValue["Time"]["Year"].asInt();
            unsigned int month = inValue["Time"]["Month"].asInt();
            unsigned int day = inValue["Time"]["Day"].asInt();
            unsigned int hour = inValue["Time"]["Hour"].asInt();
            unsigned int minute = inValue["Time"]["Minute"].asInt();
            double second = inValue["Time"]["Second"].asDouble();
            int times = inValue["CalculateTime"].asInt();

            Json::Value outValue;
            Json::FastWriter writer;

            auto mesReadRes = mesInput.Post("/ReadFile", inJson, "application/json;charset=utf-8");
            if (mesReadRes->status != 200)
            {
                outValue["State"] = "Fail";
                outValue["Reason"] = "MesReadFail";
                *outJson = writer.write(outValue);
                return false;
            }

            auto obsReadRes = obsInput.Post("/ReadFile", inJson, "application/json;charset=utf-8");
            if (obsReadRes->status != 200)
            {
                outValue["State"] = "Fail";
                outValue["Reason"] = "ObsReadFail";
                *outJson = writer.write(outValue);
                return false;
            }

            auto curTime = TimeFactory::MakeTimePtr(TimeFactory::ValueType::CommonTimeSys, year, month, day, hour, minute, second);
            if(curTime == nullptr)
            {
                Log(Debug)<<"传入时间格式错误！"<<'\n';
                return false;
            }

            int dataSize = 0;
            for (int i = 0; i < times; i++)
            {
                std::string curTimeString;
                curTime->Encode(&curTimeString);

                Json::Value obsGetValue;
                obsGetValue["FileName"] = fileName;
                obsGetValue["CurTime"] = JsonUtil::StringToValue(curTimeString);

                // Log(Debug) << JsonUtil::ValueToString(obsGetValue) << '\n';
                auto obsRes = obsInput.Post("/GetEpochRecord", JsonUtil::ValueToString(obsGetValue), "application/json;charset=utf-8");
                // Log(Debug) << obsRes->body << '\n';

                Json::Value obsResValue = JsonUtil::StringToValue(obsRes->body);
                int obsSize = obsResValue["Size"].asInt();

                Json::Value calReqValue;

                int mesSize = 0;
                for (int i = 0; i < obsSize; i++)
                {
                    Json::Value mesGetValue;
                    mesGetValue["FileName"] = fileName;
                    mesGetValue["CurTime"] = JsonUtil::StringToValue(curTimeString);
                    mesGetValue["GNSSType"] = GNSSNameUtil::GetGNSSNameByType((GNSSType)obsResValue["Content"][i]["GNSSType"].asInt());
                    mesGetValue["Serial"] = obsResValue["Content"][i]["Serial"];

                    if ((GNSSType)obsResValue["Content"][i]["GNSSType"].asInt() != GNSSType::BDS && (GNSSType)obsResValue["Content"][i]["GNSSType"].asInt() != GPS)
                        break;

                    // Log(Debug) << JsonUtil::ValueToString(mesGetValue) << '\n';
                    auto mesRes = mesInput.Post("/GetNearestRecord", JsonUtil::ValueToString(mesGetValue), "application/json;charset=utf-8");
                    if (mesRes->status != 200)
                    {
                        Log(Debug) << "error get" << '\n';
                        continue;
                    }

                    calReqValue["GNSSObsRecords"]["Content"][mesSize] = obsResValue["Content"][i];

                    calReqValue["GNSSMesRecords"]["Content"][mesSize] = JsonUtil::StringToValue(mesRes->body);
                    // Log(Debug) << mesRes->body;
                    mesSize++;
                }

                calReqValue["GNSSMesRecords"]["Size"] = mesSize;
                calReqValue["GNSSObsRecords"]["Size"] = mesSize;
                Json::Value mesGetValue;
                mesGetValue["FileName"] = fileName;
                mesGetValue["GNSSType"] = GNSSNameUtil::GetGNSSNameByType((GNSSType)obsResValue["Content"][i]["GNSSType"].asInt());
                auto mesHeaderRes = mesInput.Post("/GetHeader", JsonUtil::ValueToString(mesGetValue), "application/json;charset=utf-8");
                if (mesHeaderRes->status != 200)
                {
                    Log(Debug) << "error get" << '\n';
                    continue;
                }
                calReqValue["GNSSMesHeader"] = JsonUtil::StringToValue(mesHeaderRes->body);
                // calReqValue["GNSSObsHeader"]; // TODO

                // Log(Debug) << JsonUtil::ValueToString(calReqValue) << '\n';
                auto positionRes = calculate.Post("/Position", JsonUtil::ValueToString(calReqValue), "application/json;charset=utf-8");
                if (positionRes->status != 200)
                {
                    Log(Debug) << "定位失败！" << '\n';
                    continue;
                }

                auto velocityRes = calculate.Post("/Velocity", JsonUtil::ValueToString(calReqValue), "application/json;charset=utf-8");
                if (velocityRes->status != 200)
                {
                    Log(Debug) << "测速失败！" << '\n';
                    continue;
                }

                Json::Value position = JsonUtil::StringToValue(positionRes->body);
                Log(Info) << positionRes->body << '\n';

                Json::Value velocity = JsonUtil::StringToValue(velocityRes->body);
                Log(Info) << velocityRes->body << '\n';

                outValue["Content"][i]["Position"] = position;
                outValue["Content"][i]["Velocity"] = velocity;

                dataSize++;

                *curTime = *(curTime->TimeAfterSecond(30));
            }

            outValue["Size"] = dataSize;

            *outJson = JsonUtil::ValueToString(outValue);

            return true;
        }
    };
}